package com.etonenet.util;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Field;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Properties;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang3.StringUtils;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.Font;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.apache.poi.xssf.usermodel.XSSFFont;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class DataExportUtil {
	private final int SUCCESS = 0;
	private final int FAILURE = 1;
	private static Properties p = new Properties();
	private static Logger logger = LoggerFactory.getLogger(DataExportUtil.class);

	// static {
	// try {
	// p.load(DataExportUtil.class.getClassLoader().getResource("messageMTResource.properties").openStream());
	// } catch (IOException e) {
	// logger.error("resource file messageMTResource.properties load failed , ",
	// e);
	// }
	// try {
	// p.load(DataExportUtil.class.getClassLoader().getResource("messageMOResource.properties").openStream());
	// } catch (IOException e) {
	// logger.error("resource file messageMOResource.properties load failed , ",
	// e);
	// }
	// try {
	// p.load(DataExportUtil.class.getClassLoader().getResource("messageMTLevel3Resource.properties")
	// .openStream());
	// } catch (IOException e) {
	// logger.error("resource file messageMTLevel3Resource.properties load
	// failed , ", e);
	// }
	// }

	// /**
	// * @param key
	// * @return if key is null ,throws NullPointerException; else if the value
	// * doesn't exist ,return key; otherwise return the mapping's value ;
	// * @throws NullPointerException
	// */
	// public static String getValueByKey(String key) throws
	// NullPointerException {
	// if (key != null) {
	// String value = p.getProperty(key);
	// if (value != null) {
	// return value;
	// } else
	// logger.warn("cannot get the value with the key:" + key);
	// return key;
	// } else {
	// throw new NullPointerException("the key is null. ");
	// }
	// }
	//
	// /**
	// *
	// * @param keys
	// * String[]
	// * @return if param keys has null element, throws NullPointerException;
	// else
	// * return the mappings's values(if the key has no value mapped ,the
	// * value equals the key) for each key in params keys.
	// */
	// public static String[] getValueByKey(String[] keys) {
	// String[] values = new String[keys.length];
	// int i = 0;
	// try {
	// for (String key : keys) {
	// values[i++] = DataExportUtil.getValueByKey(key);
	// }
	// } catch (Exception e) {
	// logger.warn("The array keys has null elements");
	// return keys;
	// }
	// return values;
	// }
	//
	// /**
	// * @param headLine
	// * Excel标题栏
	// * @return 资源文件转义后的标题栏
	// */
	// public String[] getTitles(String[] resourceKeys) {
	// return getValueByKey(resourceKeys);
	// }

	private Workbook getWorkBook(String[] sheetNames, List<String[]> titles, List<List<String[]>> data, int page,
			String type) {
		if (sheetNames.length < page || titles.size() < page || data.size() < page)
			throw new IllegalArgumentException("parameters size not meet  requirement");
		Workbook wb;
		if (type.equalsIgnoreCase("xlsx"))
			wb = new SXSSFWorkbook(100); // keep 100 rows in memory, exceeding
											// rows will be flushed to disk
		else if (type.equalsIgnoreCase("xls"))
			wb = new HSSFWorkbook();
		else
			throw new IllegalArgumentException("the value of param type only be xlsx or xls");

		Font font = wb.createFont();
		font.setBoldweight(XSSFFont.BOLDWEIGHT_BOLD);

		CellStyle titleStyle = wb.createCellStyle();
		titleStyle.setFont(font);
		titleStyle.setAlignment(CellStyle.ALIGN_CENTER);
		titleStyle.setVerticalAlignment(CellStyle.VERTICAL_CENTER);

		CellStyle cellStyle = wb.createCellStyle();
		cellStyle.setAlignment(CellStyle.ALIGN_CENTER);
		cellStyle.setVerticalAlignment(CellStyle.VERTICAL_CENTER);

		Sheet sheet = null;
		Row row = null;
		Cell cell = null;

		String[] title_ = null;
		List<String[]> sheetData = null;
		String[] rowData = null;
		for (int p = 0; p < page; p++) {
			sheet = wb.createSheet();
			wb.setSheetName(p, sheetNames[p]);
			row = sheet.createRow(0);
			title_ = titles.get(p);
			for (int i = 0, len = title_.length; i < len; i++) {
				cell = row.createCell(i);
				cell.setCellStyle(titleStyle);
				cell.setCellValue(title_[i]);
			}

			sheetData = data.get(p);
			for (int currentRow = 0, size = sheetData.size(); currentRow < size; currentRow++) {
				row = sheet.createRow(currentRow + 1);
				rowData = sheetData.get(currentRow);
				for (int column = 0, len = rowData.length; column < len; column++) {
					cell = row.createCell(column);
					cell.setCellStyle(cellStyle);
					cell.setCellType(Cell.CELL_TYPE_STRING);
					cell.setCellValue(rowData[column]);
				}
			}
		}
		return wb;
	}

	/**
	 * 
	 * @param list
	 *            导出的PO/BO/VO 对象 List
	 * @param exportFields
	 *            导出对象的属性字段 String[]
	 * @param resourceKeys
	 *            属性字段对应的中文解释的资源文件keys String[]
	 * @param fileName
	 *            导出文件名
	 * @param encoding
	 *            文件编码
	 * @param clazz
	 *            导出对象的Runtime Class
	 * @param response
	 *            响应
	 * @return if return -1:不支持的导出类型; if return 1 数据导出报错; if return 0 ,导出成功;
	 */
	public static int Export(List<?> list, String[] exportFields, String[] resourceKeys, String fileName,
			String encoding, Class<?> clazz, HttpServletResponse response, HttpServletRequest request) {
		String type = fileName.substring(fileName.lastIndexOf(".") + 1);
		DataExportUtil util = new DataExportUtil();
		int result = -1;
		if (type.equalsIgnoreCase("txt") || type.equalsIgnoreCase("csv"))
			return result = util.exportByText(list, exportFields, resourceKeys, fileName, encoding, clazz, response,
					request);
		else if (type.equalsIgnoreCase("xlsx") || type.equalsIgnoreCase("xls"))
			return result = util.exportByExcel(list, exportFields, resourceKeys, fileName, encoding, clazz, response,
					request);
		else
			throw new IllegalArgumentException("only  support  txt, csv, xlsx, xls export type ...");
	}

	/**
	 * 
	 * @param list
	 *            导出的PO/BO/VO 对象 List
	 * @param exportFields
	 *            String[] 导出对象的属性字段
	 * @param clazz
	 *            导出对象的Runtime Class
	 * @return parameter list对象的属性值
	 * @throws Exception
	 */
	public List<String[]> getData(List<?> list, String[] exportFields, Class<?> clazz) throws Exception {
		SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		List<String[]> data = new ArrayList<String[]>();
		int count = exportFields.length;
		Field[] fields = new Field[count];
		Class<?> cl;
		for (int i = 0; i < count; i++) {
			try {
				fields[i] = clazz.getDeclaredField(exportFields[i]);
			} catch (NoSuchFieldException e) {
				cl = clazz.getSuperclass();
				fields[i] = cl.getDeclaredField(exportFields[i]);
			}
			fields[i].setAccessible(true);
		}
		Object o = null;
		Field f = null;
		for (Object obj : list) {
			String[] strs = new String[count];
			for (int i = 0; i < count; i++) {
				f = fields[i];
				o = f.get(obj);
				if (o != null) {
					if (f.getType() != Date.class)
						strs[i] = o.toString();
					else
						strs[i] = formatter.format(o) + "\t";
				} else
					strs[i] = "";
			}
			data.add(strs);
		}
		return data;
	}

	public int exportByExcel(List<?> list, String[] exportFields, String[] resourceKeys, String fileName,
			String encoding, Class<?> clazz, HttpServletResponse response, HttpServletRequest request) {
		response.setContentType("application/force-download;charset=UTF-8");

		final String userAgent = request.getHeader("USER-AGENT");
		try {
			if (StringUtils.contains(userAgent, "MSIE")) {// IE浏览器
				fileName = URLEncoder.encode(fileName, "UTF8");
			} else if (StringUtils.contains(userAgent, "Mozilla")) {// google,火狐浏览器
				fileName = new String(fileName.getBytes(), "ISO8859-1");
			} else {
				fileName = URLEncoder.encode(fileName, "UTF8");// 其他浏览器
			}
			response.setHeader("Content-disposition", "attachment; filename=" + fileName);
		} catch (UnsupportedEncodingException e) {
			logger.error(e.getMessage(), e);
			return FAILURE;
		}
		List<List<String[]>> data = new ArrayList<List<String[]>>();
		try {
			data.add(getData(list, exportFields, clazz));
		} catch (Exception e) {
			logger.error(e.getMessage(), e);
			return FAILURE;
		}
		ServletOutputStream out = null;
		try {
			List<String[]> firstLineList = new ArrayList<String[]>();
			firstLineList.add(resourceKeys);
			out = response.getOutputStream();
			getWorkBook(new String[] { "Sheet1" }, firstLineList, data, 1,
					fileName.substring(fileName.lastIndexOf(".") + 1)).write(out);
		} catch (Exception e) {
			logger.error(e.getMessage(), e);
			return FAILURE;
		} finally {
			try {
				out.close();
			} catch (IOException e) {
				logger.error(e.getMessage(), e);
			}
		}
		return SUCCESS;
	}

	public int exportByText(List<?> list, String[] exportFields, String[] resourceKeys, String fileName,
			String encoding, Class<?> clazz, HttpServletResponse response, HttpServletRequest request) {
		response.setContentType("application/force-download;charset=UTF-8");

		final String userAgent = request.getHeader("USER-AGENT");
		try {
			if (StringUtils.contains(userAgent, "MSIE")) {// IE浏览器
				fileName = URLEncoder.encode(fileName, "UTF8");
			} else if (StringUtils.contains(userAgent, "Mozilla")) {// google,火狐浏览器
				fileName = new String(fileName.getBytes(), "ISO8859-1");
			} else {
				fileName = URLEncoder.encode(fileName, "UTF8");// 其他浏览器
			}
			response.setHeader("Content-disposition", "attachment; filename=" + fileName);
		} catch (UnsupportedEncodingException e) {
			logger.error(e.getMessage(), e);
			return FAILURE;
		}
		StringBuffer buffer = new StringBuffer();
		String line_separator = System.getProperty("line.separator");
		{
			List<String[]> data = null;
			try {
				data = getData(list, exportFields, clazz);
			} catch (Exception e) {
				logger.error(e.getMessage(), e);
				return FAILURE;
			}
			String[] titleStrs = resourceKeys;
			for (int i = 0, len = titleStrs.length; i < len; i++) {
				buffer.append(titleStrs[i] + ",");
			}
			buffer.deleteCharAt(buffer.length() - 1);
			buffer.append(line_separator);
			for (int i = 0, size = data.size(); i < size; i++) {
				String[] data_ = data.get(i);
				for (int j = 0, length = data_.length; j < length; j++) {
					buffer.append(data_[j] + ",");
				}
				buffer.deleteCharAt(buffer.length() - 1);
				buffer.append(line_separator);
			}
		}
		ServletOutputStream out = null;
		try {
			out = response.getOutputStream();
			out.write(buffer.substring(0, buffer.length() - line_separator.length()).getBytes(encoding));
		} catch (Exception e) {
			logger.error(e.getMessage(), e);
			return FAILURE;
		} finally {
			try {
				out.close();
			} catch (IOException e) {
				logger.error(e.getMessage(), e);
				return FAILURE;
			}
		}
		return SUCCESS;
	}

}
